//日志落地类的设计（简单工厂模式）

#ifndef M_SINK_H_
#define M_SINK_H_

#include"format.hpp"

namespace bitlog{
    class LogSink{
        public:
        using ptr=shared_ptr<LogSink>;
        LogSink(){}
        virtual void log(const char* data,size_t size)=0;
    };
    class StdoutSink:public LogSink{
        public:
        using ptr=shared_ptr<StdoutSink>;
        StdoutSink(){}
        void log(const char* data,size_t size) override
        {
            cout.write(data,size);
        }
    };
    class FileSink:public LogSink{
        private:
        string _filename;
        ofstream _ofs;
        public:
        using ptr=shared_ptr<FileSink>;
        FileSink(const string& filename):_filename(filename){
            util::file::create_directory(util::file::path(_filename));
            _ofs.open(_filename,ios::app|ios::binary);
            assert(_ofs.is_open());
        }
        void log(const char* data,size_t size) override
        {
            _ofs.write(data,size);
            if(_ofs.good()==false){
                cout<<"日志输出文件失败！\n";
            }
            //这里文件流不能关闭，因为我们文件流的打开是在第一次创建这个对象时，如果我们第一次向文件中写入内容后，后续还想使用这个对象向文件中写入
            //内容时，因为第一次写入后我们将文件流关闭了，就会导致我们写入失败，_ofs.good()会返回false
            // _ofs.close();
        }
    };
    class RollBysizeSink:public LogSink{
        private:
        string _basename;
        ofstream _ofs;
        size_t _max_size;
        size_t _cur_size;
        size_t _file_count;
        public:
        using ptr=shared_ptr<RollBysizeSink>;
        RollBysizeSink(const string& basename,size_t max_size)
        :_basename(basename),_max_size(max_size),_cur_size(0),_file_count(0)
        {
            util::file::create_directory(util::file::path(basename));
        }
        void log(const char* data,size_t size) override
        {
            InitLogFile();
            _ofs.write(data,size);
            if(_ofs.good()==false){
                cout<<"日志输出文件失败\n";
            }
            _cur_size+=size;
        }
        private:
        void InitLogFile()
        {
            if(_ofs.is_open()==false||_cur_size>=_max_size){
                _ofs.close();
                string name=createname();
                _ofs.open(name,ios::binary|ios::app);
                assert(_ofs.is_open());
                _cur_size=0;
                return;
            }
            return;
        }
        string createname()
        {
            stringstream ss;
            time_t t=util::date::now();
            struct tm lt;
            localtime_r(&t,&lt);
            ss<<_basename;
            ss<<lt.tm_year+1900;
            ss<<lt.tm_mon+1;
            ss<<lt.tm_mday;
            ss<<lt.tm_hour;
            ss<<lt.tm_min;
            ss<<lt.tm_sec;
            ss<<".log";
            ss<<"-"<<++_file_count;
            return ss.str();
        }
    };
    class RollBytimeSink:public LogSink{
        private:
        string _basename;
        ofstream _ofs;
    };

    //简单工厂
    class SinkFactor{
    public:
    template<typename sinktype,typename ...Args>
    static LogSink::ptr create(Args && ...args){
        return make_shared<sinktype>(forward<Args>(args)...);
    }
    };

}



#endif